﻿namespace Bowlus.Common
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Cryptography.X509Certificates;

    using Bowlus.Common.ServiceManagement;

    using Microsoft.Practices.Unity;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.ServiceRuntime;

    public static class Settings
    {
        public const string AppHostRoleName = "Bowlus.AppHost";

        public const string DeplMgrEndPointName = "Bowlus.AppHost";

        public const string FrontEndRoleName = "Bowlus.FrontEnd";

        public const string AppContainer = "apps";

        public const string CustomizationContainer = "customizations";

        public const string TenantCustomizationContainer = "tenantcustomizations";

        public const string AppHostHttpEndpointName = "Http";

        public const string AppFrontEndSiteName = "AppFrontEnd";

        public const string SyncQueueName = "syncroles";

        public static CloudStorageAccount AzureStorageAccount
        {
            get
            {
                return CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("System.ConnectionString"));
            }
        }

        public static string ServiceName
        {
            get
            {
                return GetAzureServiceConfiguration("ManagementString")["servicename"];
            }
        }

        public static string DeploymentSlot
        {
            get
            {
                return GetAzureServiceConfiguration("ManagementString")["deploymentslot"];
            }
        }

        public static string TenantHostFromConfigFormat(string tid)
        {
            var formatString = RoleEnvironment.GetConfigurationSettingValue("NewTenantHostFormatString");

            return string.Format(formatString, tid);
        }

        public static IServiceManagementWrapper GetManagementService()
        {
            var unityContainer = BowlusContainer.Current.GetInstance<IUnityContainer>();

            return unityContainer.Resolve(typeof(IServiceManagementWrapper)) as IServiceManagementWrapper;
        }

        public static void RegisterSettingsDependencies(IUnityContainer container)
        {
            var properties = GetAzureServiceConfiguration("ManagementString");
            var subscriptionId = properties["subscription"];
            var managementThumb = properties["thumbprint"].Trim();

            var managementCert = GetManagementCertificate(managementThumb);

            if (RoleEnvironment.IsEmulated)
            {
                container.RegisterType<IServiceManagementWrapper, SimulatedServiceManagementWrapper>(
                    new ContainerControlledLifetimeManager());
            }
            else
            {
                container.RegisterType<IServiceManagementWrapper, ServiceManagementWrapper>(
                    new ContainerControlledLifetimeManager(), new InjectionConstructor(subscriptionId, managementCert));
            }
        }

        public static bool ShouldRecycleInstance(RoleEnvironmentConfigurationSettingChange configChange)
        {
            // Do not cause any recycle for any setting we use for now.
            return false;
        }

        private static IDictionary<string, string> GetAzureServiceConfiguration(string propertyName)
        {
            var managementStringParts = RoleEnvironment.GetConfigurationSettingValue(propertyName).Split(';');
            if (managementStringParts.Length != 4)
            {
                throw new ApplicationException("Wrong managementstring format");
            }


            var propertiesDict = (from nameValue in managementStringParts
                                  let property = nameValue.Split('=')
                                  select new { Name = property[0], Value = property[1] })
                                  .ToDictionary(d => d.Name, d => d.Value);
            return propertiesDict;
        }

        private static X509Certificate2 GetManagementCertificate(string managementThumb)
        {
            var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            var certs = store.Certificates.Find(X509FindType.FindByThumbprint, managementThumb, false);
            if (certs.Count < 1)
            {
                throw new ApplicationException(
                    string.Format(
                        "Cannot Locate Azure Management Certificate by Thumbprint({0}) in LocalMachine Certificate Store",
                        managementThumb));
            }

            var cert = certs[0];
            if (!cert.HasPrivateKey)
            {
                throw new ApplicationException(
                    string.Format("The management cerificate does not have a private key {0}", cert.Thumbprint));
            }

            return cert;
        }
    }
}
